﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Data.OleDb;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Markup;
using System.IO;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
using System.Text.RegularExpressions;
using LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor
{

    /// <summary>
    /// 主要用途：存放一些全局量。
    /// </summary>
    public class Globals
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态构造方法]用于初始化相关属性值。
        /// </summary>
        static Globals()
        {
            if (pathOfMyDocuments.EndsWith("\\") == false)
            {
                pathOfMyDocuments += "\\";
            }

            if (installedPath.EndsWith("\\") == false)
            {
                installedPath += "\\";
            }

            fullPathOfApp = installedPath + "LunarMarkdownEditor.exe";

            defaultWorkspacePath = installedPath + "Workspace\\";
            var oldPathOfUserFolder = PathOfMyDocuments + OldAppName + "\\";
            pathOfUserFolder = pathOfMyDocuments + AppName.Replace(" ", "-") + "\\";

            pathOfPythonScripts = pathOfUserFolder + "PythonScripts\\";
            pathOfPythonScriptResources = pathOfPythonScripts + "Resources\\";
            pathOfPythonScriptImageResources = pathOfPythonScriptResources + "Images\\";

            pathOfLmePyScripts = installedPath + "Lme_PyScripts";

            try
            {
                if (Directory.Exists(pathOfUserFolder) == false)
                {
                    if (Directory.Exists(oldPathOfUserFolder))
                    {
                        Directory.Move(oldPathOfUserFolder, PathOfUserFolder);
                    }
                    else Directory.CreateDirectory(pathOfUserFolder);
                }

                //涉及权限问题，不能创建，此目录由 Innosetup 安装时生成。
                //if (Directory.Exists(PathOfLmedPyScripts) == false)
                //{
                //    Directory.CreateDirectory(PathOfLmedPyScripts);
                //}

                if (Directory.Exists(pathOfPythonScripts) == false)
                {
                    Directory.CreateDirectory(pathOfPythonScripts);
                }

                if (Directory.Exists(pathOfPythonScriptResources) == false)
                {
                    Directory.CreateDirectory(pathOfPythonScriptResources);
                }

                if (Directory.Exists(pathOfPythonScriptImageResources) == false)
                {
                    Directory.CreateDirectory(pathOfPythonScriptImageResources);
                }

                pathOfWorkspace = pathOfUserFolder + "Workspace\\";
                if (Directory.Exists(pathOfWorkspace) == false)
                {
                    Directory.CreateDirectory(pathOfWorkspace);
                }
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show("Globals类构造方法出错：无法初始化用户目录。\r\n" + ex.Message);
            }

            hhwInstalledPath = installedPath + "HHW\\Microsoft HTML Help Workshop.exe";
            hhcInstalledPath = installedPath + "HHW\\hhc.exe";
        }

        #endregion

        private static readonly string appFullPath = System.Reflection.Assembly.GetEntryAssembly().Location;
        /// <summary>
        /// [静态只读]返回应用程序全路径。
        /// </summary>
        public static string AppFullPath
        {
            get { return Globals.appFullPath; }
        }

        /// <summary>
        /// [只读]旧应用程序名。
        /// </summary>
        public static string OldAppName { get; } = "Lunar Markdown Editor";

        private static readonly string appFileName = Assembly.GetExecutingAssembly().FullName;
        /// <summary>
        /// 当前应用程序的文件名。
        /// </summary>
        public static string AppFileName { get { return appFileName; } }

        /// <summary>
        /// 应用程序名，一般用作消息框的标题或窗口标题。
        /// 还可用下列方法：
        /// appName = System.Reflection.Assembly.GetEntryAssembly().Location;
        /// 上面这行返回：D:\My Documents\Visual Studio 2010\Projects\LunarConcept\LunarConcept\bin\Release\LunarConpect.exe
        /// Path.GetFileName(Assembly.GetEntryAssembly().GetName().CodeBase);//返回：LunarConcept.EXE
        /// </summary>
        private static readonly string appName = ((AssemblyTitleAttribute)Assembly.
            GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false)[0]).Title;
        /// <summary>
        /// [静态只读]返回应用程序（.exe文件）的短名，不含后缀名。
        /// </summary>
        public static string AppName
        {
            get { return Globals.appName; }
        }

        private static string appFormatedName = null;
        /// <summary>
        /// [只读]返回格式化的应用程序名。
        /// 格式化规则：在应用程序名中所有大写字母前面加上空格（首字母例外）。
        /// 例如：LunarConcept。格式化后为：Lunar Concept。
        /// </summary>
        public static string AppFormatedName
        {
            get
            {
                if (appFormatedName != null) return appFormatedName;

                StringBuilder sb = new StringBuilder();
                foreach (char c in appName)
                {
                    if (c >= 'A' && c <= 'Z')
                    {
                        sb.Append(' ');
                    }
                    sb.Append(c);
                }

                appFormatedName = sb.ToString().TrimStart(new char[] { ' ' });//移除首空格。
                return appFormatedName;
            }
        }

        public static string[] args;

        private static string cmdParameterString = null;
        /// <summary>
        /// 静态属性，表示命令行参数中的第一个值。
        /// App.xmal.cs文件中Application_Startup事件处理器会写这个属性的值。
        /// 
        /// 程序启动时判断有没有传入这个属性的值，如果这个值指向一个磁盘上存在的合法文档，就以此文档初始化。
        /// </summary>
        internal static string CmdParameterString
        {
            get
            {
                if (cmdParameterString.Contains(" ") == false)
                {
                    if (cmdParameterString.StartsWith("\""))
                    {
                        cmdParameterString = cmdParameterString.Substring(1);
                    }

                    if (cmdParameterString.EndsWith("\""))
                    {
                        cmdParameterString = cmdParameterString.Substring(0, cmdParameterString.Length - 1);
                    }
                }
                else
                {
                    if (cmdParameterString.StartsWith("\"") == false)
                    {
                        cmdParameterString = "\"" + cmdParameterString;
                    }

                    if (cmdParameterString.EndsWith("\"") == false)
                    {
                        cmdParameterString += "\"";
                    }
                }

                StringBuilder longPath = new StringBuilder(255);
                _WinApis.GetLongPathName(cmdParameterString, longPath, longPath.Capacity);
                return longPath.ToString();
            }
            set
            {
                cmdParameterString = value;
            }
        }


        /// <summary>
        /// 终于解决了输入法的问题。
        /// 原先使用WinForm的输入法控制库终究不行——取不出当前输入法名称。
        /// </summary>
        /// <param name="enable">开、关。</param>
        public static void SwitchInputMethod(bool enable)
        {
            if (MainWindow == null) return;

            if (enable)
            {
                var typeOfLanguage = new System.Globalization.CultureInfo("zh-cn");
                InputLanguage.CurrentInputLanguage = InputLanguage.FromCulture(typeOfLanguage);

                InputMethod.SetIsInputMethodEnabled(MainWindow, enable);
                InputMethod.Current.ImeState = InputMethodState.On;
            }
            else
            {
                var typeOfLanguage = new System.Globalization.CultureInfo("en-us");
                InputLanguage.CurrentInputLanguage = InputLanguage.FromCulture(typeOfLanguage);
            }
        }

        public static bool InputMethodIsOpen
        {
            get
            {
                if (InputLanguage.CurrentInputLanguage.Culture.Name != "zh-ch") return false;
                if (InputMethod.Current.ImeState == InputMethodState.On) return true;

                return false;
            }
        }

        private static readonly string documentName = "MarkDown文件";
        /// <summary>
        /// [只读]返回程序自定义的文档类别的描述性（短）文本。
        /// ——值为“MarkDown文件”。
        /// </summary>
        public static string DocumentName
        {
            get { return Globals.documentName; }
        }

        private static readonly string extensionName = "md";
        /// <summary>
        /// [只读]返回程序自定义文档类别的后缀名。★不含“.”。
        /// ——值为“txt”。
        /// </summary>
        public static string ExtensionName
        {
            get { return Globals.extensionName; }
        }

        private static string fullPathOfApp;
        /// <summary>
        /// [只读]返回应用程序运行时的全路径。
        /// </summary>
        public static string FullPathOfApp
        {
            get { return Globals.fullPathOfApp; }
        }

        private static string installedPath = System.AppDomain.CurrentDomain.BaseDirectory;
        /// <summary>
        /// [只读]取程序“安装（运行）目录”。
        /// 不要轻易使用这个目录，因为账户安全控制的原因——可能根本无法向此目录中写入任何文件。
        /// 所以配置文件什么的都不应该放在这个目录中。
        /// </summary>
        public static string InstalledPath
        {
            get { return Globals.installedPath; }
        }

        /// <summary>
        /// InstalledPath的别名。
        /// </summary>
        public static string RunningPath
        {
            get { return Globals.installedPath; }
        }

        /// <summary>
        /// 表示当前应用程序的主窗口。
        /// </summary>
        public static MainWindow MainWindow
        {
            get
            {
                MainWindow mainWindow = App.Current.MainWindow as MainWindow;
                return mainWindow;
            }
        }

        private static string defaultWorkspacePath;
        /// <summary>
        /// 默认工作区目录路径。在程序运行目录下的“Workspace”子目录下。不可更改。
        /// </summary>
        public static string DefaultWorkspacePath
        {
            get { return Globals.defaultWorkspacePath; }
        }

        private static string pathOfWorkspace;
        /// <summary>
        /// 当前工作区目录的路径。可以更改。
        /// </summary>
        public static string PathOfWorkspace
        {
            get
            {
                if (string.IsNullOrEmpty(Globals.pathOfWorkspace) || Directory.Exists(Globals.pathOfWorkspace) == false)
                {
                    pathOfWorkspace = Globals.defaultWorkspacePath;
                }

                if (string.IsNullOrEmpty(pathOfWorkspace) == false && pathOfWorkspace.EndsWith("\\") == false)
                {
                    pathOfWorkspace += "\\";
                }

                return Globals.pathOfWorkspace;
            }
            set
            {
                Globals.pathOfWorkspace = value;
                if (Globals.pathOfWorkspace.EndsWith("\\") == false)
                {
                    Globals.pathOfWorkspace += "\\";
                }
            }
        }

        private static string pathOfWorkspaceAssetsFolder;
        /// <summary>
        /// 当前工作区目录的附件文件夹路径。不可以手工更改。
        /// </summary>
        public static string PathOfWorkspaceAssetsFolder
        {
            get
            {
                if (string.IsNullOrWhiteSpace(Globals.pathOfWorkspace)) return "";

                return Globals.pathOfWorkspace + "$_Assets~\\";
            }
        }

        /// <summary>
        /// 当前工作区下 reveal.js 库的位置
        /// </summary>
        public static string PathOfWorkspaceRevealJs
        {
            get
            {
                return Globals.PathOfWorkspace + "_reveal-js\\";
            }
        }

        /// <summary>
        /// 工作区根目录下的“Images~”子目录，以“\\”结尾。
        /// </summary>
        public static string PathofWorkspaceImages
        {
            get { return Globals.PathOfWorkspace + "Images~\\"; }
        }

        /// <summary>
        /// 当前工作区脚本使用的图标文件夹路径。以 "\" 结尾。
        /// </summary>
        public static string PathOfWorkspaceScriptImageResourceFolder
        {
            get
            {
                var path = Globals.PathOfWorkspace + @"_PythonScripts~\_Resources~\_Images~\\";
                if (Directory.Exists(path) == false)
                {
                    try
                    {
                        Directory.CreateDirectory(path);
                    }
                    catch (Exception ex)
                    {
                        LMessageBox.ShowWarning("无法创建脚本调用按钮图标资源目录！错误信息如下：\r\n\r\n　　" + ex.Message);
                    }
                }
                return path;
            }
        }

        /// <summary>
        /// 当前工作区目录的短名。
        /// </summary>
        public static string WorkspaceShortName
        {
            get
            {
                if (string.IsNullOrEmpty(Globals.PathOfWorkspace)) return "";

                if (Directory.Exists(Globals.PathOfWorkspace) == false) return "";

                DirectoryInfo di = new DirectoryInfo(Globals.PathOfWorkspace);
                return di.Name;
            }
        }

        private static readonly string pathOfMyDocuments = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        /// <summary>
        /// [只读]返回Windows操作系统中定义的“我的文档”这个特殊文件夹所指向的实际路径。
        /// </summary>
        public static string PathOfMyDocuments
        {
            get { return Globals.pathOfMyDocuments; }
        }

        public static string PathOfDeskTop
        {
            get { return Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); }
        }

        private static string pathOfUserFolder;
        /// <summary>
        /// [只读]用户目录。
        /// </summary>
        public static string PathOfUserFolder
        {
            get { return pathOfUserFolder; }
        }

        private static string pathOfPythonScripts;
        /// <summary>
        /// [只读]Python脚本目录。
        /// </summary>
        public static string PathOfPythonScripts
        {
            get { return pathOfPythonScripts; }
        }

        private static string pathOfPythonScriptResources;
        /// <summary>
        /// [只读]Python脚本使用的资源文件目录，例如 Images 目录的父目录。
        /// </summary>
        public static string PathOfPythonScriptResources
        {
            get { return pathOfPythonScriptResources; }
        }

        private static string pathOfPythonScriptImageResources;
        /// <summary>
        /// [只读]Python 脚本使用的图像文件目录。
        /// </summary>
        public static string PathOfPythonScriptImageResources
        {
            get { return pathOfPythonScriptImageResources; }
        }

        public static string PathOfWorkspacePythonScripts
        {
            get
            {
                var path = PathOfWorkspace + "_PythonScripts~\\";
                try
                {
                    if (System.IO.Directory.Exists(path) == false)
                    {
                        Directory.CreateDirectory(path);
                    }
                    return path;
                }
                catch { return null; }
            }
        }

        public static string PathOfWorkspacePythonScriptResources
        {
            get
            {
                var path = PathOfWorkspacePythonScripts + "_Rsources~\\";
                try
                {
                    if (System.IO.Directory.Exists(path) == false)
                    {
                        Directory.CreateDirectory(path);
                    }
                    return path;
                }
                catch { return null; }
            }
        }

        public static string PathOfWorkspacePythonScriptImageResources
        {
            get
            {
                var path = PathOfWorkspacePythonScriptResources + "_Images~\\";
                try
                {
                    if (System.IO.Directory.Exists(path) == false)
                    {
                        Directory.CreateDirectory(path);
                    }
                    return path;
                }
                catch { return null; }
            }
        }

        private static string pathOfLmePyScripts;
        /// <summary>
        /// [只读]LME 内置的 Python 脚本的目录。
        /// 在启动时，会自动将这些脚本文件复制到 PathOfPythonScripts 路径下使用。
        /// 为什么要这样做？
        ///   这是因为 LME 默认安装路径可能存在读、写权限问题！而 Python 脚本应是开放的，允许用户随时根据需要修改的。
        /// </summary>
        public static string PathOfLmedPyScripts
        {
            get { return pathOfLmePyScripts; }
        }

        /// <summary>
        /// 当前工作区使用的模板文件，不一定存在，由用户决定。
        /// </summary>
        public static string PathOfWorkspaceCommonTemplateFile
        {
            get { return PathOfWorkspace + "common~.tmp"; }
        }

        /// <summary>
        /// 用户词典文件的完整路径名。位置在：PathOfUserFolder + "Dict.txt";
        /// </summary>
        public static string PathOfUserDictionary
        {
            get { return PathOfUserFolder + "Dict.txt"; }
        }

        /// <summary>
        /// 工作区词典文件的完整路径名。位置在：PathOfWorkspace + "Dict.txt";
        /// </summary>
        public static string PathOfWorkspaceDictionary
        {
            get { return PathOfWorkspace + "Dict.txt"; }
        }

        /// <summary>
        /// 用于存放各 Markdown 文件中的“锚”片段的文本文件。其格式如下：
        /// 
        /// xxx\xxx\xxx.md
        ///     [anchor1 text2](@anchor1Id anchor1 text1)
        ///     [anchor2 text2](@anchor2Id anchor2 text1)
        /// 其中，路径为全小写，顶格；属于此路径的“锚”文本片段则以一个 Tab 符开头。
        /// 
        /// 两个文件的锚之间，以空行分隔。
        /// 
        /// 锚的定义中，字面值1（text1）和字面值2（text2）均可省略，且不省略时可带空格，使用时，优先使用字面值1；
        /// 每个 Markdown 文件在保存时，都会将其相对于工作区目录的短路径的小写版字串和文件中所有的锚文本片段拼成上面的值写到此属性指明的文件末尾。
        /// 写文件时，不考虑文件中是否已经存在同样的路径的旧版本。
        /// 编译工作区时，重写此文件中的内容，以最新的版本覆盖旧的版本。（这个机制有些类似 CSS）
        /// </summary>
        public static string PathOfWorkspaceAnchorsFilePath
        {
            get { return PathOfWorkspace + "Anchors~.txt"; }
        }

        /// <summary>
        /// [只读]记载历史导出目录信息的文件的路径。
        /// </summary>
        public static string PathOfHistoryOutputFileFullName
        {
            get { return PathOfUserFolder + "HistoryOutport.txt"; }
        }

        /// <summary>
        /// [只读]记载历史工作区目录信息的文件的路径。
        /// </summary>
        public static string PathOfHistoryWorkspaceFileFullName
        {
            get { return PathOfUserFolder + "HistoryWorkspaces.txt"; }
        }

        /// <summary>
        /// html help workshop的安装路径。
        /// </summary>
        internal static string hhwInstalledPath;
        /// <summary>
        /// Html Help Compiler(hhc.exe)安装路径。
        /// </summary>
        internal static string hhcInstalledPath;

        private static string sysFontFamily = "Consolas,SimSun";
        /// <summary>
        /// 默认系统字体名称。
        /// </summary>
        public static string SysFontFamily
        {
            get { return sysFontFamily; }
            set { sysFontFamily = value; }
        }

        /// <summary>
        /// 用于开启模拟 Vim 移动模式的按键。半秒之内连续点击两次这个键就可以开启此模式。
        /// 在此模式下，按下键盘上的部分按钮（例如：i），会返回正常编辑模式。
        /// 这个按键可以改变为Key.RightShift。
        /// </summary>
        public static Key VimKey { get; set; } = Key.LeftShift;

        /// <summary>
        /// 用户环境变量文件的路径。
        /// </summary>
        public static string PathOfUserEnvironmentValuesFilePath
        {
            get { return PathOfUserFolder + "EnvironmentValues.txt"; }
        }

        /// <summary>
        /// 工作区环境变量文件的路径。
        /// </summary>
        public static string PathOfWorkspaceEnvironmentValuesFilePath
        {
            get { return PathOfWorkspace + "EnvironmentValues.txt"; }
        }

        /// <summary>
        /// 适合使用自定义 Python 脚本创建自定义菜单项、工具条按钮时载入图标。
        /// 会自动到 PythonScripts/Resources/Images 目录下去查找文件。
        /// </summary>
        /// <param name="imageName">如果文件在 Python 脚本目录的资源目录下，可以只提供文件短名（含后缀）。</param>
        /// <returns></returns>
        public static Image LoadImage(string imageName)
        {
            if (string.IsNullOrWhiteSpace(imageName))
                return null;

            var imagePath = imageName;
            if (File.Exists(imageName) == false)
            {
                if (Directory.Exists(Globals.PathOfPythonScriptImageResources))
                {
                    imagePath = Globals.PathOfPythonScriptImageResources + imageName;
                }
            }
            if (File.Exists(imagePath))
                return new Image() { Source = LoadBitmapImageFromFile(imagePath), };
            else return null;
        }

        /// <summary>
        /// 载入图像文件。
        /// </summary>
        /// <param name="imageFilePath"></param>
        /// <returns></returns>
        public static BitmapImage LoadBitmapImageFromFile(string imageFilePath)
        {
            if (File.Exists(imageFilePath) == false) return null;
            try
            {
                using (BinaryReader reader = new BinaryReader(File.Open(imageFilePath, FileMode.Open)))
                {
                    FileInfo fi = new FileInfo(imageFilePath);
                    byte[] bytes = reader.ReadBytes((int)fi.Length);
                    reader.Close();

                    var bitmapImage = new BitmapImage();
                    bitmapImage.BeginInit();
                    bitmapImage.StreamSource = new MemoryStream(bytes);
                    bitmapImage.EndInit();
                    return bitmapImage;
                }
            }
            catch (Exception ex)
            {
                LMessageBox.Show(ex.Message, Globals.appName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return null;
            }
        }

        /// <summary>
        /// 给 IronPython 调用，用来调用另一个 Python 脚本文件。目的是截获异常消息。
        /// 实践说明：直接在脚本中为 MenuItem 或 ToolBarButton 的 Click 事件 += Event_Handler 方法无法截获异常。
        /// </summary>
        /// <param name="scriptName"></param>
        public static void RunScript(string scriptName)
        {
            var scriptFullPath = scriptName;
            if (File.Exists(scriptName) == false)
            {
                scriptFullPath = Globals.PathOfPythonScripts + scriptName;
            }

            if (File.Exists(scriptFullPath) == false)
            {
                LMessageBox.Show($"没有找到名为【scriptFullPath】的脚本文件。", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            PythonScriptListItem.RunScript(PythonScriptListItem.PythonScriptCallMode.Default, scriptFullPath, true);
        }

        public static void RunWorkspaceScript(string scriptName)
        {
            var scriptFullPath = scriptName;
            if (File.Exists(scriptName) == false)
            {
                scriptFullPath = Globals.PathOfWorkspacePythonScripts + scriptName;
            }

            if (File.Exists(scriptFullPath) == false)
            {
                LMessageBox.Show($"没有在工作区脚本目录下找到名为【scriptFullPath】的脚本文件。", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            PythonScriptListItem.RunScript(PythonScriptListItem.PythonScriptCallMode.Default, scriptFullPath, true);
        }

        /// <summary>
        /// 检查指定文档中的图像链接（Markdown格式）指向的图像文件是否存在。
        /// </summary>
        /// <param name="onlyActiveEditor"></param>
        public static void ValidateImageLinks(bool onlyActiveEditor = true)
        {
            if (onlyActiveEditor)
            {
                var fdtvi = MainWindow.ActivedEditor.ValidateImageLinks();

                if (fdtvi.Items.Count > 0)
                {
                    Globals.MainWindow.tvFindAndReplace.Items.Clear();
                    Globals.MainWindow.tvFindAndReplace.Items.Add(fdtvi);

                    if (Globals.MainWindow.tcRightToolBar.SelectedItem != Globals.MainWindow.tiFindResult)
                    {
                        Globals.MainWindow.tcRightToolBar.SelectedItem = Globals.MainWindow.tiFindResult;
                    }

                    if (Globals.MainWindow.cdRightToolsArea.ActualWidth < 140)
                    {
                        Globals.MainWindow.cdMainEditArea.Width =
                            Globals.MainWindow.cdRightToolsArea.Width = new GridLength(3, GridUnitType.Star);
                    }
                }
            }
            else
            {
                List<FindDocumentTreeViewItem> fds = new List<FindDocumentTreeViewItem>();
                foreach (var me in Globals.MainWindow.Editors)
                {
                    var fdtvi = me.ValidateImageLinks();
                    if (fdtvi != null && fdtvi.Items.Count > 0) fds.Add(fdtvi);
                }

                if (fds.Count > 0)
                {
                    Globals.MainWindow.tvFindAndReplace.Items.Clear();
                    foreach (var fd in fds)
                    {
                        Globals.MainWindow.tvFindAndReplace.Items.Add(fd);
                    }

                    if (Globals.MainWindow.tcRightToolBar.SelectedItem != Globals.MainWindow.tiFindResult)
                    {
                        Globals.MainWindow.tcRightToolBar.SelectedItem = Globals.MainWindow.tiFindResult;
                    }

                    if (Globals.MainWindow.cdRightToolsArea.ActualWidth < 140)
                    {
                        Globals.MainWindow.cdMainEditArea.Width =
                            Globals.MainWindow.cdRightToolsArea.Width = new GridLength(3, GridUnitType.Star);
                    }
                }
            }
        }

        public static void ValidateImageLinksInWorkspace()
        {
            MainWindow.tvFindAndReplace.Items.Clear();

            List<FindDocumentTreeViewItem> findResultList = new List<FindDocumentTreeViewItem>();
            ValidateImageLinksInAFile(MainWindow.tvWorkDirectory.Items[0] as WorkspaceTreeViewItem, ref findResultList);

            if (findResultList.Count <= 0)
            {
                LMessageBox.Show("未发现无效图像链接！", Globals.appName, MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            foreach (var fd in findResultList)
            {
                MainWindow.tvFindAndReplace.Items.Add(fd);
            }

            if (Globals.MainWindow.tcRightToolBar.SelectedItem != Globals.MainWindow.tiFindResult)
            {
                Globals.MainWindow.tcRightToolBar.SelectedItem = Globals.MainWindow.tiFindResult;
            }

            if (Globals.MainWindow.cdRightToolsArea.ActualWidth < 140)
            {
                Globals.MainWindow.cdMainEditArea.Width =
                    Globals.MainWindow.cdRightToolsArea.Width = new GridLength(3, GridUnitType.Star);
            }
        }

        private static void ValidateImageLinksInAFile(WorkspaceTreeViewItem item, ref List<FindDocumentTreeViewItem> findResultList)
        {
            if (item == null || item.IsAborted) return;

            switch (item.ItemType)
            {
                case WorkspaceTreeViewItem.Type.Folder:
                    {
                        // 先处理自身
                        if (IsEncripied(item.FullPath))
                        {
                            findResultList.Add(new FindDocumentTreeViewItem(item.FullPath, item.Title, "【加密文档－忽略】" + item.Title));
                        }
                        else
                        {
                            ValidateImageLinksInAFile(item.FullPath, item.ShortName, item.Title, ref findResultList);
                        }

                        // 再处理子级
                        var subItems = item.Items;
                        if (subItems.Count > 0)
                        {
                            foreach (var subItem in subItems)
                            {
                                ValidateImageLinksInAFile(subItem as WorkspaceTreeViewItem, ref findResultList);
                            }
                        }
                        break;
                    }
                case WorkspaceTreeViewItem.Type.File:
                    {
                        if (IsEncripied(item.FullPath))
                        {
                            findResultList.Add(new FindDocumentTreeViewItem(item.FullPath, item.Title, "【加密文档－忽略】" + item.Title));
                        }
                        else
                        {
                            // 只处理自身
                            ValidateImageLinksInAFile(item.FullPath, item.ShortName, item.Title, ref findResultList);
                        }
                        break;
                    }
            }
        }

        private static void ValidateImageLinksInAFile(string fileFullPath, string shortName, string title, ref List<FindDocumentTreeViewItem> findResultList)
        {
            if (File.Exists(fileFullPath) == false || findResultList == null) return;

            try
            {
                FindDocumentTreeViewItem fdtvi = new FindDocumentTreeViewItem(fileFullPath, shortName, "【无效链接】 " + title) { IsExpanded = true, };

                using (StreamReader streamReader = new StreamReader(fileFullPath))
                {
                    var lineNumber = 1;
                    var totalLength = 0;
                    var temp = streamReader.ReadLine();
                    List<TextlineInfo> lineInfos = new List<TextlineInfo>();

                    while (temp != null)
                    {
                        var lineInfo = new TextlineInfo()
                        {
                            Number = lineNumber,
                            Offset = totalLength,
                            Text = temp,
                        };
                        lineInfos.Add(lineInfo);

                        if (temp.EndsWith("\r\n"))
                        {
                            totalLength += temp.Length;
                        }
                        else
                        {
                            totalLength += temp.Length;
                            totalLength += 2;
                        }

                        temp = streamReader.ReadLine();
                        lineNumber++;
                    }

                    foreach (var lineInfo in lineInfos)
                    {
                        var regImageLink = new Regex(@"!\[.*?\]\(.*?\)");
                        var lineMatches = regImageLink.Matches(lineInfo.Text);

                        foreach (Match m in lineMatches)
                        {
                            var imageLink = m.Value;
                            Regex imageTitleReg = new Regex(@"(?<=(!\[)).*(?=\])");
                            Regex relativePathReg = new Regex(@"(?<=(!\[.*\]\()).*(?=[ )])");
                            var imageTitleMatch = imageTitleReg.Match(imageLink);
                            var relativePathMatch = relativePathReg.Match(imageLink);

                            if (relativePathMatch.Success && imageTitleMatch.Success)
                            {
                                var imageTitle = imageTitleMatch.Value;
                                var relativeImagePath = relativePathMatch.Value;
                                var imagePath = MarkdownEditor.ConvertRelativeImageLinkPathToFull(relativeImagePath, fileFullPath);
                                if (File.Exists(imagePath) == false)
                                {
                                    FindLineTreeViewItem ftvi = new FindLineTreeViewItem(fileFullPath, shortName, lineInfo.Number,
                                        relativePathMatch.Index, relativeImagePath.Length, lineInfo.Text,
                                        Brushes.Black, FindLineTreeViewItem.ItemType.Normal);
                                    fdtvi.Items.Add(ftvi);
                                }
                            }
                        }
                    }
                }

                if (fdtvi.Items.Count > 0)
                {
                    findResultList.Add(fdtvi);
                }
            }
            catch
            {
                return;
            }
        }

        class TextlineInfo
        {
            public int Number { get; set; }
            public int Offset { get; set; }
            public int EndOffset { get { return Offset + Length; } }
            public string Text { get; set; }
            public int Length { get { return Text.Length; } }
        }

        /// <summary>
        /// 判断指定路径的 Markdown 文件是否被加密。
        /// </summary>
        /// <param name="fullFilePath"></param>
        /// <returns></returns>
        public static bool IsEncripied(string fullFilePath)
        {
            return MarkdownEditor.IsEncripied(fullFilePath);
        }

        /// <summary>
        /// 终于解决了输入法的问题。
        /// 原先使用WinForm的输入法控制库终究不行——取不出当前输入法名称。
        /// </summary>
        /// <param name="enable">开、关。</param>
        //public static void SwitchInputMethod(bool enable)
        //{
        //    if (MainWindow == null) return;

        //    InputMethod.SetIsInputMethodEnabled(MainWindow, false);

        //    InputMethod.Current.ImeState = enable ? InputMethodState.On : InputMethodState.Off;
        //}

        /// <summary>
        /// 验证传入的身份证号是否合法。
        /// </summary>
        /// <param name="idCardText">应传入待验证的身份证号。</param>
        /// <returns>如果合法，返回 true。</returns>
        public static bool ValidateIdCard(string idCardText)
        {
            if (string.IsNullOrWhiteSpace(idCardText)) return false;
            return (_IdCard.CheckCidInfo18(idCardText) == "" || _IdCard.CheckCidInfo15(idCardText) == "");
        }

        /// <summary>
        /// 验证传入的银行卡号是否有效。
        /// </summary>
        /// <param name="savingCardNumberText"></param>
        /// <returns>如果合法，返回 true。</returns>
        public static bool ValidateSavingCard(string savingCardNumberText)
        {
            return _SavingCard.ValidateSavingCardNumber(savingCardNumberText);
        }
    }
}
